// use num::complex::Complex;
fn main() {
    // 编译器会进行自动推导，给予twenty i32的类型
    let twenty = 20;

    // 类型标注
    let x: i32 = 11;

    // 通过类型后缀的方式进行类型标注：22是i32类型
    let y = 22i32;
  
    // 只有同样类型，才能运算
    let z = x + y;
  
    // 对于较长的数字，可以用_进行分割，提升可读性
    let z = 100_000;
  
    // 浮点数默认推导为f64
    // 定义一个f32数组，其中42.0会自动被推导为f32类型
    let ar = [42.0, 42f32];
  
    // 打印数组中第一个值，并控制小数位为2位
    println!("{}, {:.2}, {:.2e}", ar[0], ar[0], ar[0]); // "{}"可展示基本类型

    // 生成连续的1-4和'a'到'd'
    for i in 1..=4 {
        print!("{} ", i);
    }
    for i in 'a'..='d' {
        print!("{} ", i) // 这里漏了分号也能跑。详见下文
    }

    // 复数计算
    // let ca = Complex { re: 2.1, im: -1.2 };
    // let cb = Complex::new(11.1, 22.2);
    // let result = ca + cb;
    // println!("{} + {}i", result.re, result.im)

    // 将 3.14 四舍五入
    println!("{}", 3.14_f32.round());

    // 字符、布尔类型和单元类型
    // 所有的 Unicode 值都可以作为 Rust 字符，占4个字节
    let c :char = '我';
    let b :bool = true;
    let u :() = ();

    println!("'我'的大小: {}", std::mem::size_of_val(&c));


    {
        let x = 2; // 语句，不返回值
        x + 1; // 语句
        () // 默认返回()
    }
    // 表达式如果不返回任何值，会隐式地返回一个 () 
    // 三元表达式
    let t = if x % 2 == 0 { "even" } else { "odd" };

    
    let p = add_two(x, y); // 基本类型(及不可变引用、部分元组)是可*Copy*的，会在栈上做自动拷贝，不会涉及所有权
    println!("{} + {} = {}", x, y, p);


    // main 函数有返回值，返回单元类型 ()。无返回类型的专称发散函数
    // 单元类型 ()的用法和 Go 语言的 struct{} 类似，不占内存
  }

// 函数名和变量名使用蛇形命名法(snake case)
// Rust 不关心我们在哪里定义了函数，只要有定义即可
// 每个函数参数都需要标注类型
fn add_two(x : i32, y :i32) -> i32 {
    x + y // 表达式，总会返回值。在语句块的末尾时充当返回值
}

// 当然我们也可以使用 return 提前返回
// 默认返回()

// 当用 ! 作函数返回类型的时候，表示该函数永不返回( diverge function )，特别的，这种语法往往用做会导致程序崩溃的函数
fn to_end() -> ! {
    panic!("终点")
}